package cn.jinjimi.domain.data;

import android.text.TextUtils;

import cn.jinjimi.base.util.GsonUtils;
import cn.jinjimi.app.controller.event.DataEvent;
import cn.jinjimi.app.controller.event.NetworkErrorEvent;
import cn.jinjimi.domain.Dispatcher;
import cn.jinjimi.domain.ServiceManager;
import cn.jinjimi.app.entity.BaseResponse;
import cn.jinjimi.app.store.DatabaseManager;

import java.io.IOException;

import retrofit2.Response;

/**
 * Created by zhenhua on 16/7/22.
 */
public abstract class Store {

    public static void dispatch(Object event) {
        ServiceManager.getService(Dispatcher.class).dispatch(event);
    }

    public static <T extends DataEvent> void success(Class<T> tClass, Object data) {
        dispatch(tClass, DataEvent.SUCC, 0, "OK", data);
    }

    public static <T extends DataEvent> void fail(Class<T> tClass, int code, Object message) {
        dispatch(tClass, DataEvent.FAIL, code, message, null);
    }

    public static <T extends DataEvent> void fail(Class<T> tClass) {
        dispatch(tClass, DataEvent.FAIL, NetworkErrorEvent.ERROR_IO_CODE, NetworkErrorEvent.ERROR_IO_MESSAGE, null);
    }

    public static <T extends DataEvent> void dispatch(Class<T> tClass, int state, int code, Object message, Object data) {
        ServiceManager.getService(Dispatcher.class).dispatch(
                EventFactory.create(tClass, state, code, message, data)
        );
    }

    public static <T, E extends DataEvent> T parseDataAndDispatchEvents(Response<T> response, E event) {
        T data = null;
        int state = DataEvent.FAIL;

        if (response != null
                && response.isSuccessful()
                && response.body() != null) {

            data = response.body();
            state = DataEvent.SUCC;
        }

        int code = response == null ?
                NetworkErrorEvent.ERROR_IO_CODE : response.code();

        String msg = response == null ?
                NetworkErrorEvent.ERROR_IO_MESSAGE : response.message();

        if (event != null) {
            dispatch(EventFactory.create(event, state, code, msg, data));
        }

        return data;
    }

    public static <T, D, E extends DataEvent> D parseDataAndDispatchEvents(Response<T> response, E event, DataAdapter<T, D> adapter) {
        D data = null;
        int state = DataEvent.FAIL;

        if (response != null
                && response.isSuccessful()
                && response.body() != null) {

            data = adapter.getData(response.body());
            state = DataEvent.SUCC;
        }

        int code = response == null ?
                NetworkErrorEvent.ERROR_IO_CODE : response.code();

        String msg = response == null ?
                NetworkErrorEvent.ERROR_IO_MESSAGE : response.message();

        if (event != null) {
            dispatch(EventFactory.create(event, state, code, msg, data));
        }

        return data;
    }

    public static <E extends BaseResponse> E getHttpState(Response<E> response, E data) {
        if (response != null && response.isSuccessful() && response.body() != null) {
            data = response.body();
            data.isOk = true;
            data.statusCode = response.code();
            data.statusMsg = response.message();
            data.errorBody = null;
        } else {
            data.isOk = false;
            data.statusCode = response != null ? response.code() : -1;
            data.statusMsg = response != null ? response.message() : "";
            try {
                data.errorBody = response != null ? response.errorBody().string() : "";
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return data;
    }

    public interface DataAdapter<T, D> {
        D getData(T data);
    }

    public <T extends BaseResponse> T getResponse(Response<T> response) throws IOException {
        return getResponse(response, null, false, false, null);
    }

    public <T extends BaseResponse> T getResponse(Response<T> response, Class clss, boolean cache, boolean cacheWithLoginState, String cacheKey) throws IOException {
        cache = cache && !TextUtils.isEmpty(cacheKey);
        T t = null;
        if (response != null && response.isSuccessful() && response.body() != null) {
            t = response.body();
            if (cache && response.body().retCode != null && response.body().retCode.startsWith("2")) {
                DatabaseManager.getInstance().getCacheDao().saveCacheData(t, cacheKey, cacheWithLoginState);
            }
        } else if (cache) {
            String str = DatabaseManager.getInstance().getCacheDao().getCacheData(cacheKey, cacheWithLoginState);
            if (!TextUtils.isEmpty(str)) {
//                Class cls = response.getClass();
//                Type superclass = cls.getGenericSuperclass();
//                if (superclass instanceof ParameterizedType) {
//                    ParameterizedType mParameterizedType = (ParameterizedType) superclass;
//                    Type[] mActualTypeArguments = mParameterizedType.getActualTypeArguments();
//                    if (mActualTypeArguments != null && mActualTypeArguments.length > 0) {
//                        t = GsonUtils.fromJson(str, mActualTypeArguments[0]);
//                    }
//                }
                t = (T) GsonUtils.fromJson(str, clss);
            }
        }
        if (t == null) {
            //网络错误
            if (response == null) {
                throw new IOException();
            }
            //HTTP错误
            if (!response.isSuccessful()) {
                throw new IOException(response.message());
            }
        } else if (t.retCode != null && !t.retCode.startsWith("2")) {
            //服务器返回错误
            throw new IOException(t.retCode);
        }
        return t;
    }
}
